package com.load.ctrls.imp;

import java.sql.*;
import java.util.*;

import javax.sql.*;

import org.apache.log4j.*;
import org.springframework.jdbc.core.*;
import org.springframework.jdbc.core.simple.*;

import com.database.objects.*;
import com.load.ctrls.*;
import com.load.objects.*;

public class ElementCtrl implements IElementCtrl {

	private static final long serialVersionUID = -4191044276972093504L;

	private static Logger logger = Logger.getLogger("load.repository");

	private SimpleJdbcTemplate jdbcTemplate;

	@Override
	public void calculateConstantineCohesionForClasses(Developer developer) {
		logger.info("DEVELOPER: " + developer.getName() + " - START CALCULATE CONSTANTINE COHESION FOR CLASSES");

		long ini = System.currentTimeMillis();
		List<ClassWrapper> classes = findClassesByDeveloper(developer);
		logger.info("DEVELOPER: " + developer.getName() + " - " + classes.size() + " classes");
		logger.info("DEVELOPER: " + developer.getName() + " - Time obtaining classes: " + (System.currentTimeMillis() - ini));

		ini = System.currentTimeMillis();
		int index = 1;
		for (ClassWrapper clazz : classes) {
			Double numAttributes = Double.valueOf(clazz.getNumFields());
			Double numMethods = Double.valueOf(clazz.getNumberMethods());
			Double sumMethodsAccess = 0.0;
			for (String field : clazz.getFields()) {
				sumMethodsAccess += Double.valueOf(clazz.getNumMethodsAccessField(field));
			}

			Double constantineCohesion = numMethods > 1 && numAttributes > 0 ? (numMethods - (sumMethodsAccess / numAttributes)) / (numMethods - 1) : 0.0;
			clazz.setConstantineCohesion(constantineCohesion);
			logger.info("DEVELOPER: " + developer.getName() + " - CLASS: " + index + " - " + clazz.getId());
			index++;
		}
		System.out.println("Time calculating cohesion for a developer: " + (System.currentTimeMillis() - ini));

		updateConstantineCohesionClass(classes);

		logger.info("DEVELOPER: " + developer.getName() + " - Time calculate constantine cohesion: " + (System.currentTimeMillis() - ini));
		logger.info("DEVELOPER: " + developer.getName() + " - FINISH CALCULATE CONSTANTINE COHESION");
	}

	private List<ClassWrapper> findClassesByDeveloper(Developer developer) {
		String sqlClasses = "select cla_id from class cla inner join file fil on fil.fil_id = cla.fil_id inner join commit com on com.com_id = fil.com_id where dev_id = ? order by cla_id";
		String sqlFields = "select fie_name from field where cla_id = ?";
		String sqlMethods = "select met_id, met_content from method where cla_id = ?";
		String sqlVariables = "select var_name from variable where met_id = ?";

		RowMapper<ClassWrapper> mapperClasses = new RowMapper<ClassWrapper>() {
			@Override
			public ClassWrapper mapRow(ResultSet rs, int rowNum) throws SQLException {
				Integer classId = rs.getInt("cla_id");
				return new ClassWrapper(classId);
			}
		};

		RowMapper<String> mapperFields = new RowMapper<String>() {
			@Override
			public String mapRow(ResultSet rs, int rowNum) throws SQLException {
				return rs.getString("fie_name");
			}
		};

		RowMapper<MethodWrapper> mapperMethods = new RowMapper<MethodWrapper>() {
			@Override
			public MethodWrapper mapRow(ResultSet rs, int rowNum) throws SQLException {
				Integer id = rs.getInt("met_id");
				String content = rs.getString("met_content");
				return new MethodWrapper(id, content);
			}
		};

		RowMapper<String> mapperVariables = new RowMapper<String>() {
			@Override
			public String mapRow(ResultSet rs, int rowNum) throws SQLException {
				return rs.getString("var_name");
			}
		};

		List<ClassWrapper> classes = jdbcTemplate.query(sqlClasses, mapperClasses, developer.getId());
		Iterator<ClassWrapper> iterator = classes.iterator();
		while (iterator.hasNext()) {
			ClassWrapper clazz = iterator.next();
			List<String> fields = jdbcTemplate.query(sqlFields, mapperFields, clazz.getId());
			List<MethodWrapper> methods = jdbcTemplate.query(sqlMethods, mapperMethods, clazz.getId());
			Iterator<MethodWrapper> iterator1 = methods.iterator();
			while (iterator1.hasNext()) {
				MethodWrapper method = iterator1.next();
				List<String> variables = jdbcTemplate.query(sqlVariables, mapperVariables, method.getId());
				method.setVariables(variables);
			}
			clazz.setFields(fields);
			clazz.setMethods(methods);
		}

		return classes;
	}

	private void updateConstantineCohesionClass(List<ClassWrapper> classes) {
		String sql = "update class set cla_constantine_cohesion = ? where cla_id = ?;";
		List<Object[]> paramsList = new ArrayList<Object[]>();
		for (ClassWrapper clazz : classes) {
			Object[] params = new Object[] { clazz.getConstantineCohesion(), clazz.getId() };
			paramsList.add(params);
		}
		jdbcTemplate.batchUpdate(sql, paramsList);
	}

	public void setDataSource(DataSource dataSource) {
		jdbcTemplate = new SimpleJdbcTemplate(dataSource);
	}

}